//
// Created by antler on 2018/12/6.
//

#include "Color3B.h"

#include <cmath>

#include "log.h"
#include "GlobalMacros.h"

#include "luaext/color3f/Color3F.h"
#include "luaext/utils/StringUtils.h"

Color3B *Color3B::create() {
    return new(std::nothrow)Color3B();
}

Color3B *Color3B::createWith(int rgb) {
    return new(std::nothrow)Color3B(rgb);
}

Color3B *Color3B::createWith(int r, int g, int b) {
    return new(std::nothrow)Color3B(r, g, b);
}

Color3B *Color3B::createWith(const std::string &rgb) {
    return createWith(StringUtils::stoi(rgb, 0));
}

Color3B *Color3B::createWith(const Color3F &c3f) {
    return new(std::nothrow)Color3B(c3f);
}

Color3B *Color3B::createWith(const Color3B &c3b) {
    return new(std::nothrow)Color3B(c3b);
}

Color3B::Color3B() {
    r = g = b = 0;
}

Color3B::Color3B(int rgb) {
    r = ARGB_R(rgb);
    g = ARGB_G(rgb);
    b = ARGB_B(rgb);
}

Color3B::Color3B(int r, int g, int b) {
    this->r = r & 0xFF;
    this->g = g & 0xFF;
    this->b = b & 0xFF;
}

Color3B::Color3B(const Color3F &c3f) {
    int rgb = c3f.toInt();
    r = ARGB_R(rgb);
    g = ARGB_G(rgb);
    b = ARGB_B(rgb);
}

int Color3B::toInt() const {
    return SetRGB(r, g, b);
}

std::string Color3B::toString() const {
    char buf[32];
    sprintf(buf, "0x%06x", toInt());
    return buf;
}

static double colorDistance(const Color3B &c1, const Color3B &c2) {
    int rmean = (c1.r + c2.r) / 2;
    int r = c1.r - c2.r;
    int g = c1.g - c2.g;
    int b = c1.b - c2.b;
    return std::sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
}

//bool Color3B::isEqual(const Color3B &other, int offset, int fuzziness) {
//#define COLOR_TOLERANCE (6)
//
////    if (fuzziness == 100) {
//    return (r == other.r && g == other.g && b == other.b);
////    }
//
////    double colorDist = colorDistance(Color3B(rr, gg, bb), other);
////    double colorDiff = COLOR_TOLERANCE - colorDist;
////    int percent = colorDiff * 100 / COLOR_TOLERANCE;
////
////    LOGV("isEqual [%d,%d,%d] [%d,%d,%d] colorDist:%f, colorDiff:%d, fuzziness:%d, percent:%d", rr,
////         gg, bb,
////         other.r, other.g, other.b, colorDist, colorDiff, fuzziness, percent);
////
////    if (percent <= (100 - fuzziness)) {
////        return true;
////    }
//
////    return false;
//}

bool Color3B::isEqual(const Color3B &other, int offset, int fuzziness) {
    if (offset != COLOR_INVALID) {
        int color = toInt();
        int otherColor = other.toInt();
        int minColor = std::max(otherColor - offset & 0xFFFFFF, 0x000000);
        int maxColor = std::min(otherColor + offset & 0xFFFFFF, 0xFFFFFF);
        if (minColor <= color && color <= maxColor) {
            return true;
        }
    } else {
        return (r == other.r && g == other.g && b == other.b);
    }

    return false;
}

